﻿/*
 *  Copyright 2010 www.jaxmao.org
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Security.Cryptography;

namespace SafeBox
{
    public partial class MainWindow : Form
    {
        private Hashtable items = null;
        private string fileName = null;

        private bool changed = false;

        private byte[] secretKey = null;
        private byte[] iv = null;


        public MainWindow()
        {
            this.items = new Hashtable();
            this.secretKey = null;
            InitializeComponent();


        }

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            string n = this.itemList.SelectedItem as string;
            if (n != null)
            {
                this.itemDetail.Text = this.items[n] as string;
                this.itemName.Text = n;
                this.itemName.ReadOnly = true;
                this.itemDetail.ReadOnly = true;
                this.editButton.Enabled = true;
            }
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            if (this.openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                if (this.secretKey == null)
                {
                    PasswordDialog pd = new PasswordDialog();
                    if (pd.ShowDialog(this) == DialogResult.OK && (!string.IsNullOrEmpty(pd.passwordText) && pd.passwordText.Length >=4))
                    {
                        this.setSecret(pd.passwordText.Trim());
                    }
                }
                this.openFile(this.openFileDialog1.FileName);
                this.resetSecret();
                this.currentFile.Text = this.openFileDialog1.FileName;
                this.fileName = this.openFileDialog1.FileName;
            }

        }

        private void openFile(string fileName)
        {
            this.items.Clear();
            this.itemList.Items.Clear();
            this.itemName.Text = "";
            this.itemDetail.Text = "";

            try
            {
                CryptionTool decrypt = new CryptionTool();
                this.items = decrypt.decryptItems(fileName, this.secretKey);
                if (items != null && items.Keys.Count > 0)
                {
                    foreach (string item in this.items.Keys)
                    {
                        this.itemList.Items.Add(item);
                        //                    this.itemName.Text = item;
                        //                    this.itemDetail.Text = this.items[item] as string;
                        //                    this.itemList.SelectedIndex = this.itemList.Items.Count - 1;
                    }
                }
            }
            catch (CryptographicException ex)
            {
                MessageBox.Show("Sorry, the password you entered is not valid.  Can't decrypt this file.");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void closeButton_Click(object sender, EventArgs e)
        {
            this.items.Clear();
            this.itemList.Items.Clear();
            this.itemName.Text = "";
            this.itemDetail.Text = "";
        }

        private void clear()
        {
            this.itemDetail.Text = "";
            this.itemName.Text = "";
        }

        private void newButton_Click(object sender, EventArgs e)
        {
            NewItemDialog item = new NewItemDialog();

            this.itemName.ReadOnly = false;
            this.itemDetail.ReadOnly = false;
            if (item.ShowDialog(this) == DialogResult.OK)
            {
                this.newItem(item.ItemName, item.ItemDetail);
            }
        }

        public void newItem(string itemName, string detail)
        {
            if (itemName != String.Empty && detail != String.Empty)
            {
                if (this.items.Contains(itemName))
                {
                    this.items.Remove(itemName);
                }
                else
                {
                    this.itemList.Items.Add(itemName);
                }
                this.items.Add(itemName, detail);
                if (this.itemList.Items.Count > 0)
                {
                    this.itemList.SelectedIndex = this.itemList.Items.Count - 1;
                }

                this.changed = true;
                this.saveButton.Enabled = true;
            }
        }

        private void toolStripButton1_Click_1(object sender, EventArgs e)
        {
            AboutSafeWay about = new AboutSafeWay();
            about.ShowDialog(this);
        }

        private void cutButton_Click(object sender, EventArgs e)
        {
            this.changed = true;
            this.saveButton.Enabled = true;
            int num = this.itemList.SelectedIndex;
            if (num >= 0)
            {
                if (MessageBox.Show("Do you really want to delete \"" + this.itemList.SelectedItem + "\"?", "Confirm delete", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    string n = this.itemList.SelectedItem as string;
                    this.itemList.Items.Remove(n);
                    this.items.Remove(n);
                    if (this.itemList.Items != null)
                    {
                        if (num < this.itemList.Items.Count)
                        {
                            this.itemList.SelectedIndex = num;
                        }
                        else
                        {
                            this.itemList.SelectedIndex = this.itemList.Items.Count - 1;
                        }
                    }

                    if (this.itemList.Items == null || this.itemList.Items.Count < 1)
                    {
                        this.itemDetail.Text = "";
                        this.itemName.Text = "";
                    }
                }
            }
        }

        private void saveButton_Click(object sender, EventArgs e)
        {
            try
            {
                if (this.items.Count > 0)
                {
                    if (String.IsNullOrEmpty(this.fileName))
                    {
                        this.saveFileDialog.DefaultExt = "sbx";
                        this.saveFileDialog.AddExtension = true;
                        if (this.saveFileDialog.ShowDialog(this) == DialogResult.OK)
                        {
                            this.fileName = this.saveFileDialog.FileName;
                        }
                    }
                    if (this.secretKey == null)
                    {
                        Password pwd = new Password();

                        if (pwd.ShowDialog(this) == DialogResult.OK)
                        {
                            this.setSecret(pwd.PasswordText);
                        }
                    }

                    CryptionTool encryt = new CryptionTool();
                    encryt.encryptItems(this.items, this.fileName, this.secretKey);
                    this.changed = false;
                    this.saveButton.Enabled = false;
                }
                else
                {
                    MessageBox.Show("Nothing to be saved.");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void setSecret(string pwdText)
        {
            if (string.IsNullOrEmpty(pwdText))
            {
            }
            else
            {
                SHA256Managed sha = new SHA256Managed();
                secretKey = sha.ComputeHash(Encoding.UTF8.GetBytes(pwdText));
            }
        }

        private void resetSecret()
        {
            this.secretKey = null;
        }

        private void saveAs(string fileName)
        {
            if (this.secretKey == null)
            {
                Password pwd = new Password();

                if (pwd.ShowDialog(this) == DialogResult.OK)
                {
                    this.setSecret(pwd.PasswordText);
                }
            }
            try
            {
                XmlDocument xmlDoc = new XmlDocument();
                XmlTextWriter xmlWriter = null;
                FileStream stream = null;

                try
                {
                    RijndaelManaged rm = new RijndaelManaged();

                    rm.GenerateIV();

                    byte[] IV = rm.IV;
                    this.iv = rm.IV;

                    stream = new FileStream(this.fileName, FileMode.OpenOrCreate, FileAccess.Write);
                    
                    /*
                    stream.Write(IV, 0, IV.Length);
                    MessageBox.Show("k=" + this.secretKey.Length + " iv=" + IV.Length);
                    stream.Flush();
                    */

                    using (CryptoStream csEncrypt = new CryptoStream(stream, rm.CreateEncryptor(this.secretKey, this.iv), CryptoStreamMode.Write))
                    {
                        using (StreamWriter sWriter = new StreamWriter(csEncrypt, Encoding.UTF8))
                        {
                            xmlWriter = new XmlTextWriter(sWriter);
                            xmlWriter.Formatting = Formatting.Indented;
                            xmlWriter.WriteProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");

                            if (this.items != null && this.items.Count > 0)
                            {
                                XmlElement root = xmlDoc.CreateElement("Items");
                                foreach (string key in this.items.Keys)
                                {
                                    XmlElement item = xmlDoc.CreateElement("Item");
                                    XmlElement itemName = xmlDoc.CreateElement("Name");
                                    XmlCDataSection name = xmlDoc.CreateCDataSection(key);
                                    itemName.AppendChild(name);
                                    item.AppendChild(itemName);
                                    XmlElement itemDetail = xmlDoc.CreateElement("Detail");
                                    XmlCDataSection detail = xmlDoc.CreateCDataSection(this.items[key] as string);
                                    itemDetail.AppendChild(detail);
                                    item.AppendChild(itemDetail);

                                    root.AppendChild(item);
                                }
                                xmlDoc.AppendChild(root);
                                xmlDoc.WriteContentTo(xmlWriter);
                            }
                            else
                            {
                                MessageBox.Show("Nothing to be saved.");
                            }

                            csEncrypt.Flush();

                        }
                    }
                }
                finally
                {
                    if (xmlWriter != null)
                    {
                        xmlWriter.Close();
                    }
                    if (stream != null)
                    {
                        stream.Close();
                    }
                    this.resetSecret();
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.GetType().Name+": "+ex.ToString());
            }
        }

        private void Xdecrypt(Stream stream, byte[] key, byte[] IV)
        {
            try
            {
                try
                {
                    RijndaelManaged rm = new RijndaelManaged();
                    using (CryptoStream csDecrypt = new CryptoStream(stream, rm.CreateDecryptor(key, IV), CryptoStreamMode.Read))
                    {
                        using (StreamReader sReader = new StreamReader(csDecrypt, Encoding.UTF8))
                        {

                            XmlDocument xmldoc = new XmlDocument();

                            try
                            {
                                xmldoc.Load(sReader);

                                XmlNodeList list = xmldoc.SelectNodes("Items/Item");

                                foreach (XmlNode node in list)
                                {
                                    XmlNodeList children = node.ChildNodes;
                                    string n = null;
                                    string d = null;
                                    foreach (XmlNode child in children)
                                    {
                                        if (child.Name.Equals("Name"))
                                        {
                                            n = child.InnerText;
                                        }
                                        else if (child.Name.Equals("Detail"))
                                        {
                                            d = child.InnerText;
                                        }
                                    }
                                    if (n != String.Empty && d != String.Empty)
                                    {
                                        this.items.Add(n, d);
                                        this.itemList.Items.Add(n);
                                        this.itemList.SelectedIndex = this.itemList.Items.Count - 1;
                                    }
                                }

                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show(ex.ToString());
                            }


                        }
                    }
                }
                finally
                {
                    if (stream != null)
                    {
                        stream.Close();
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.GetType().Name + ": " + ex.ToString());
            }

        }

        private void newFileButton_Click(object sender, EventArgs e)
        {
            this.items.Clear();
            this.itemList.Items.Clear();
            this.itemName.Text = "";
            this.itemDetail.Text = "";
        }

        private void exitButton_Click(object sender, EventArgs e)
        {
            if (this.changed)
            {
                if (MessageBox.Show("Do you want to discard the changes?", "Confirm Changes", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    this.Dispose();
                }
            }
            else
            {
                this.Dispose(true);
            }
        }

        private void clearButton_Click(object sender, EventArgs e)
        {
            this.itemName.Text = String.Empty;
            this.itemDetail.Text = String.Empty;
        }

        private void toolStripButton1_Click_2(object sender, EventArgs e)
        {
            NewItemDialog item = new NewItemDialog();

            item.ItemName = this.itemName.Text;
            item.ItemDetail = this.itemDetail.Text;

            this.editButton.Enabled = true;
            if (item.ShowDialog(this) == DialogResult.OK)
            {
                this.newItem(item.ItemName, item.ItemDetail);
            }

        }
    }
}
